/**
 * Created by quliang on 16-4-7 下午3:15
 * Copyright (c) 2016 SAIZ.CN. All rights reserved.
 */

package com.example.db.utils;


import android.util.Log;

import com.example.db.common.SaizConstant;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonNull;
import com.google.gson.JsonParser;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;


public final class JsonUtil {
    private static final String TAG = "jsonUtil";
    private static Gson gson;

    static {
        GsonBuilder gb = new GsonBuilder();
        // 不导出实体中没有用@Expose注解的属性
        gb.excludeFieldsWithoutExposeAnnotation();
        // 支持Map的key为复杂对象的形式
        gb.enableComplexMapKeySerialization();
        // 时间转化为特定格式
        gb.setDateFormat(SaizConstant.DEF_DATETIME_FORMAT);
        // 序列化null字段
        gb.serializeNulls();
        // 会把字段首字母大写
        // gb.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE);
        // 对json结果格式化.
        // gb.setPrettyPrinting();
        // 版本号来选择是否要序列化.
        gb.setVersion(1.0);
        gson = gb.create();
    }

    public static String encode(Map<String, ?> src) {
        return getJsonString(src);
    }

    public static String encode(Serializable src) {
        return getJsonString(src);
    }

    @SuppressWarnings("unchecked")
    public static Map<String, ?> decode(String json) {
        Log.d(TAG, json);
        return decode(json, HashMap.class);
    }

    public static <T extends Serializable> T decode(String json, Class<T> clzss) {
        Log.d(TAG, json);
        return decode(getJsonElement(json), clzss);
    }

    public static <T extends Serializable> List<T> decodeArray(String json, Class<T> clzss) {
        Log.d(TAG, json);
        return decodeArray(getJsonElement(json), clzss);
    }


    public static <T extends Serializable> T decode(JsonElement element, Class<T> clzss) {
        return getJsonObject(element, clzss);
    }

    public static <T extends Serializable> List<T> decodeArray(JsonElement element,
                                                               Class<T> clzss) {
        return getJsonObject(element, clzss);
    }

    public static JsonElement getJsonElement(String json) {
        Log.d(TAG, json);
        JsonParser parser = new JsonParser();
        return parser.parse(json);
    }

    public static String getJsonString(Object src) {
        return gson.toJson(src);
    }

    public static <T> T getJsonObject(JsonElement element, Type type) {
        if (element == null) {
            return null;
        }
        if (element.isJsonArray()) {
            return gson.fromJson(element, getListType(element, type));
        }
        return gson.fromJson(element, type);
    }

    private static Type getListType(JsonElement element, Type type) {
        JsonArray arr = element.getAsJsonArray();
        ListToken token = new ListToken();
        Iterator<JsonElement> elit = arr.iterator();
        JsonElement ele = elit.hasNext() ? elit.next() : JsonNull.INSTANCE;
        if (!ele.isJsonArray()) {
            token.addType(type);
            return token;
        }
        token.addType(getListType(ele, type));
        return token;
    }

    private static final class ListToken implements ParameterizedType {
        private Type type;

        public void addType(Type type) {
            this.type = type;
        }

        @Override
        public Type[] getActualTypeArguments() {
            return new Type[]{type};
        }

        @Override
        public Type getRawType() {
            return List.class;
        }

        @Override
        public Type getOwnerType() {
            return null;
        }
    }

}
